package serie11;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.Observable;
import java.util.Observer;

import javax.swing.BorderFactory;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;

import serie11.PetModel.State;

public class Pet {
	
	// ATTRIBUTS
	
	private static final int WIDTH = 500, HEIGHT = 500, W = 20, H = 30;
	
	// La fenetre principale.
	private JFrame frame;
	
	// La barre des menus.
	private JMenuBar jmb;
	
	// Les 3 menus
	private JMenu file;
	private JMenu edit;
	private JMenu quit;
	
	// Les items des diff�rents menus
	private JMenuItem newf;
	private JMenuItem newFromFile;
	private JMenuItem open;
	private JMenuItem reopen;
	private JMenuItem save;
	private JMenuItem saveAs;
	private JMenuItem close;
	private JMenuItem clear;
	private JMenuItem quit2;
	
	// La zone de texte.
	private JTextArea text;
	
	// Le panneau de d�filement.
	private JScrollPane jsp;
	
	// Labels g�rant la barre de statut.
	private JLabel statusBar1;
	private JLabel statusBar2;
	private JLabel statusBar3;
	
	// Le mod�le.
	private PetModel model;
	// JFileChooser permettant le choix d'un fichier.
	private JFileChooser fc;
	
	// CONSTRUCTEUR
	
	public Pet() {
		createModel();
        createView();
        placeComponents();
        createController();
		model.notifyObservers();
	}
	
	// COMMANDES

    /**
     * Rend l'application visible au centre de l'ecran.
     */
    public void display() {
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    
    // OUTILS
    
    private void createModel() {
    	model = new StdPetModel();
    }
    
    private void createView() {
        frame = new JFrame("Petit Editeur de Texte");
        frame.setPreferredSize(new Dimension(WIDTH, HEIGHT));
        newf = new JMenuItem("New");
        newFromFile = new JMenuItem("New From File...");
        open = new JMenuItem("Open...");
        reopen = new JMenuItem("Reopen");
        reopen.setEnabled(false);
        save = new JMenuItem("Save");
        save.setEnabled(false);
        saveAs = new JMenuItem("Save as...");
        saveAs.setEnabled(false);
        close = new JMenuItem("Close");
        clear = new JMenuItem("Clear");
        quit2 = new JMenuItem("Quit");
        clear.setEnabled(false);
        file = new JMenu("File");
        edit = new JMenu("Edit");
        quit = new JMenu("Quit");
        jmb = new JMenuBar();
        text = new JTextArea(W, H);
        text.setBackground(Color.BLACK);
        text.setForeground(Color.WHITE);
        text.setCaretColor(Color.WHITE);
        fc = new JFileChooser();
        jsp = new JScrollPane();
        statusBar1 = new JLabel("Fichier :");
        statusBar2 = new JLabel("");
        statusBar3 = new JLabel("<aucun>");
        // Observateur 1
        model.addObserver(new Observer() {
			public void update(Observable arg0, Object arg1) {
				// diff�rents boutons
				if (text.getText().equals("")) {
					clear.setEnabled(false);
				} else {
					clear.setEnabled(true);
				}
				if (!model.isSynchronized() 
						&& model.getState() == State.FIL_DOC) {
					reopen.setEnabled(true);
					save.setEnabled(true);
				} else {
					reopen.setEnabled(false);
					save.setEnabled(false);
				}
				if (model.getDocument() != null) {
					saveAs.setEnabled(true);
					close.setEnabled(true);
					if (model.getDocument().getLength() > 0) {
						clear.setEnabled(true);
					} else {
						clear.setEnabled(false);
					}
				} else {
					saveAs.setEnabled(false);
					close.setEnabled(false);
					clear.setEnabled(false);
				}
			}
        });
        // Observateur 2
        model.addObserver(new Observer() {
			public void update(Observable arg0, Object arg1) {
				if (model.getDocument() == null) { 
					jsp.setViewportView(null);	
				} else {
					jsp.setViewportView(text);
					text.requestFocusInWindow();
					if (text.getDocument() != model.getDocument()) {
						text.setDocument(model.getDocument());
					}
				}
			}
        });
        // Observateur 3
        model.addObserver(new Observer() {
			public void update(Observable arg0, Object arg1) {
				if (model.getState() == State.FIL_DOC) {
					if (model.isSynchronized()) {
						statusBar2.setText(" ");
					} else {
						statusBar2.setText("*");
					}
					statusBar3.setText(model.getFile().getName());
				} else {
					statusBar3.setText("<aucun>");
					if (model.getDocument() == null) {
						statusBar2.setText("");
					} else {
						statusBar2.setText("*");
					}
				}
			}
        });
    }
  
    
    private void placeComponents() {
        file.add(newf);
        file.add(newFromFile);
        file.addSeparator();
        file.add(open);
        file.add(reopen);
        file.addSeparator();
        file.add(save);
        file.add(saveAs);
        file.add(close);
        jmb.add(file);
        edit.add(clear);
        quit.add(quit2);
        jmb.add(edit);
        jmb.add(quit);
    	frame.setJMenuBar(jmb);
    	frame.add(jsp, BorderLayout.CENTER);
    	JPanel p = new JPanel(new BorderLayout()); {
    		JPanel q = new JPanel(); {
    			q.add(statusBar1);
        		q.add(statusBar2);
        		q.add(statusBar3);
    		}
    		p.add(q, BorderLayout.WEST);
    	}
    	p.setBorder(BorderFactory.createEtchedBorder());
    	frame.add(p, BorderLayout.SOUTH);
    }
    
    private void createController() {
    	frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    	frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent arg0) {
				if (!model.isSynchronized() && model.getDocument() != null) {
					int res = jOptPane1();
					if (res == JOptionPane.YES_OPTION) {
						if (model.getFile() == null) {
							// saveAs
							if (saveAs() == 1) {
								// le saveAs s'est bien d�roul�
								System.exit(0);
							}
						} else {
							// save
							save();
		    				System.exit(0);
						}
					} else if (res == JOptionPane.NO_OPTION) {
						System.exit(0);
					}
				} else {
					System.exit(0);
				}
			}
    	});
    	quit2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (!model.isSynchronized() && model.getDocument() != null) {
					int res = jOptPane1();
					if (res == JOptionPane.YES_OPTION) {
						if (model.getFile() == null) {
							// saveAs
							saveAs();
		    				System.exit(0);
						} else {
							// save
							save();
		    				System.exit(0);
						}
					} else if (res == JOptionPane.NO_OPTION) {
						System.exit(0);
					} 
				} else {
					System.exit(0);
				}
			} 
    	});
    	clear.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					int l = model.getDocument().getLength();
					model.getDocument().remove(0, l);
					model.notifyObservers();
				} catch (BadLocationException e1) {
					jOptPane2("du traitement");
				}
				
			}
    	});
    	newf.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				model.createEmptyDoc();
				model.notifyObservers();
			}
    	});
    	newFromFile.addActionListener(new ActionListener() {
    		public void actionPerformed(ActionEvent e) {
				int choice = fc.showOpenDialog(null);
				if (choice == JFileChooser.APPROVE_OPTION) {
					try {
						model.createEmptyDoc();
						model.setFile(fc.getSelectedFile());
						model.load();
						model.removeFile();
						model.notifyObservers();
					} catch (IOException e1) {
						jOptPane2("du chargement");
					} catch (BadLocationException e1) {
						jOptPane2("du chargement");
					}
				}
			}
    	});
    	open.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				int choice = fc.showOpenDialog(null);
				if (choice == JFileChooser.APPROVE_OPTION) {
					try {
						model.createEmptyDoc();
						model.setFile(fc.getSelectedFile());
						model.load();
						model.notifyObservers();
					} catch (IOException e1) {
						jOptPane2("du chargement");
					} catch (BadLocationException e1) {
						jOptPane2("du chargement");
					}
				}
			}
    	});
    	reopen.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					model.createEmptyDoc();
					model.load();
					model.notifyObservers();
				} catch (IOException e1) {
					jOptPane2("du chargement");
				} catch (BadLocationException e1) {
					jOptPane2("du chargement");
				}
			}
    	});
    	save.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				save();
			}
    	});
    	saveAs.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				saveAs();
			}
    	});
    	close.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				model.removeDocument();
				model.removeFile();
				model.notifyObservers();
			}
    	});
    }
    
    // OUTILS
    
    private int jOptPane1() {
    	return JOptionPane.showConfirmDialog(
            	null,
            	"Souhaitez-vous enregistrer les modifications ?",
            	"Enregistrer les modifications",
            	JOptionPane.YES_NO_CANCEL_OPTION,
            	JOptionPane.WARNING_MESSAGE
			);
    }
    
    private void jOptPane2(String s) {
    	JOptionPane.showMessageDialog(
		    null,
		    "Erreur lors " + s + " du fichier",
		    "ERREUR !!!",
		    JOptionPane.ERROR_MESSAGE
    	);
    }
    
    /**
     * Sauvegarde le contenu du document dans le fichier. 
     */
    private void save() {
    	try {
			model.save();
			model.notifyObservers();
		} catch (IOException e1) {
			jOptPane2("de la sauvegarde");
		} catch (BadLocationException e1) {
			jOptPane2("de la sauvegarde");
		}
    }
    
    /**
     * Demande un nouveau fichier � l'utilisateur, fixe le fichier du mod�le 
     *  avec ce fichier et sauvegarde le contenu du document dans le fichier.
     * @return
     */
    private int saveAs() {
    	int choice = fc.showSaveDialog(null);
		if (choice == JFileChooser.APPROVE_OPTION) {
			File file2 = fc.getSelectedFile();
				try {
					if (!file2.isFile()) {
					    file2.createNewFile();
					}
					model.setFile(file2);
					model.save();
					model.notifyObservers();
				} catch (IOException e1) {
					jOptPane2("de la sauvegarde");
				} catch (BadLocationException e1) {
					jOptPane2("de la sauvegarde");
				}
			return 1;	
		} else {
			return 0;
		}
    }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Pet().display();
            }
        });
    }

}
